package edu.uci.ics.ai.maze.views;

import edu.uci.ics.ai.maze.models.GameModel;
import edu.uci.ics.ai.maze.utils.TimeUtils;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.util.Observable;
import java.util.Observer;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JTextField;

public class StatsDialog extends JDialog implements Observer {

  private final JMenuItem showStatsMenuItem;
  private final JTextField searchTimeField = new JTextField();
  private final JTextField pathCostField = new JTextField();

  // Used by addNotify
  private boolean frameSizeAdjusted = false;
  
  public StatsDialog(JFrame parent, GameModel model, JMenuItem showStatsMenuItem) {
    super(parent, "Statistics Window");

    this.showStatsMenuItem = showStatsMenuItem;
    setResizable(false);
    getContentPane().setLayout(new GridBagLayout());
    setSize(304, 57);

    JButton closeButton = new JButton("Close");
    getContentPane().add(closeButton,
            new GridBagConstraints(3, 0, 1, 2, 1.0, 1.0,
            GridBagConstraints.CENTER, GridBagConstraints.NONE,
            new Insets(5, 0, 5, 5), 0, 20));
    closeButton.setBounds(228, 6, 67, 45);
    closeButton.addActionListener(new CloseButtonListener());

    JLabel searchTimeLabel = new JLabel("Search time in ms");
    getContentPane().add(searchTimeLabel,
            new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0,
            GridBagConstraints.WEST, GridBagConstraints.BOTH,
            new Insets(5, 5, 5, 5), 0, 0));
    searchTimeLabel.setFont(new Font("Dialog", Font.PLAIN, 12));
    searchTimeLabel.setBounds(6, 5, 136, 21);

    JLabel pathCostLabel = new JLabel("Path Cost");
    getContentPane().add(pathCostLabel,
            new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0,
            GridBagConstraints.WEST, GridBagConstraints.BOTH,
            new Insets(0, 5, 5, 5), 0, 0));
    pathCostLabel.setFont(new Font("Dialog", Font.PLAIN, 12));
    pathCostLabel.setBounds(6, 31, 136, 21);

    searchTimeField.setEditable(false);
    getContentPane().add(searchTimeField,
            new GridBagConstraints(1, 0, 2, 1, 10.0, 1.0,
            GridBagConstraints.CENTER, GridBagConstraints.BOTH,
            new Insets(5, 0, 5, 5), 0, 0));
    searchTimeField.setBounds(147, 5, 73, 21);
    searchTimeField.setText("0");

    pathCostField.setDisabledTextColor(new Color(153, 153, 153));
    pathCostField.setEditable(false);
    getContentPane().add(pathCostField,
            new GridBagConstraints(1, 1, 2, 1, 10.0, 1.0,
            GridBagConstraints.CENTER, GridBagConstraints.BOTH,
            new Insets(0, 0, 5, 5), 0, 0));
    pathCostField.setBounds(147, 31, 73, 21);
    pathCostField.setText(String.valueOf(0));

    model.addObserver(this);
  }

  @Override
  public void setVisible(boolean b) {
    if (b) {
      showStatsMenuItem.setEnabled(false);
    } else {
      showStatsMenuItem.setEnabled(true);
    }

    super.setVisible(b);
  }

  @Override
  public void addNotify() {
    // Record the size of the window prior to calling parents addNotify.
    Dimension size = getSize();

    super.addNotify();

    if (frameSizeAdjusted) {
      return;
    }
    frameSizeAdjusted = true;

    // Adjust size of frame according to the insets
    Insets insets = getInsets();
    setSize(insets.left + insets.right + size.width,
            insets.top + insets.bottom + size.height);
  }

  /**
   * @param searchTime the searchTime (in ns) to set
   */
  public void setSearchTime(long searchTime) {
    DecimalFormat formatter = new DecimalFormat("0.00");
    double time = Math.round(TimeUtils.nsToMs(searchTime) * 100) / 100.0;
    this.searchTimeField.setText(formatter.format(time));
  }

  /**
   * @param pathCost the pathCost to set
   */
  public void setPathCost(double pathCost) {
    this.pathCostField.setText(Double.toString(pathCost));
  }

  @Override
  public void update(Observable o, Object arg) {
    if (arg == GameModel.Observations.UPDATE_PATH) {
      GameModel model = (GameModel) o;

      setSearchTime(model.getSearchResult().getSearchTime());
      setPathCost(model.getSearchResult().getPathCost());
      setVisible(true);
      repaint();

    }
  }

  private class CloseButtonListener implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent event) {
      setVisible(false);
    }
  }
}
